#ifndef XXK_CAN_H
#define XXK_CAN_H

#include "xcanps.h"


#include "../XXK.h"
#include "../IRQ.h"
#include "../Xxk_DDR/Xxk_DDR.h"


#define STANDARD_FRAME 0U
#define EXTENDED_FRAME 1U

#define XCANPS_MAX_FRAME_SIZE_IN_WORDS  (XCANPS_MAX_FRAME_SIZE / sizeof(u32))
#define FRAME_DATA_LENGTH	8U


#define BTR_SYNCJUMPWIDTH		3  // 同步跳转宽度 取值范围 ：0~3
#define BRPR_BAUD_PRESCALAR	    9  // 预分频系数 取值范围：0~63
#define BTR_FIRST_TIMESEGMENT	15 // TEG1 取值范围： 0~15
#define BTR_SECOND_TIMESEGMENT	2  // TEG2 取值范围：0~7
// buad = can_clk / (BRPR_BAUD_PRESCALAR+1) / (BTR_SECOND_TIMESEGMENT + BTR_FIRST_TIMESEGMENT + 3)
// buad = 100 / (9+1) / (15+2+3) = 0.5MHz
// buad = 100 / (4+1) / (15+7+3) = 0.8MHz
// buad = 100 / (4+1) / (15+2+3) = 1MHz


extern XCanPs psCan0;


// psCan初始化
int psCanInti(XCanPs* psCanPtr, u16 psCan_DeviceId);
//psCanInti(&psCan0, XPAR_XCANPS_0_DEVICE_ID);


int psCanSet(XCanPs* psCanPtr, u8 Prescaler, u8 SyncJumpWidth, u8 TimeSegment2, u8 TimeSegment1);
//psCanSet(&psCan0, BRPR_BAUD_PRESCALAR, BTR_SYNCJUMPWIDTH, BTR_SECOND_TIMESEGMENT, BTR_FIRST_TIMESEGMENT);


extern void XCanPs_EnterMode(XCanPs *InstancePtr, u8 OperationMode);
//XCanPs_EnterMode(&psCan0, XCANPS_MODE_NORMAL); // CAN进入正常收发模式
//while (XCanPs_GetMode(&psCan0) != XCANPS_MODE_NORMAL)
//    ; // 等待进入正常收发模式

void psCan_IntrSetAndEnable(XScuGic *scuGicPtr, u32 psCan_IntrId, XCanPs *psCanPtr, u32 mask);
//psCan_IntrSetAndEnable(&scuGic, XPAR_XCANPS_0_INTR, &psCan0, XCANPS_IXR_ALL);

void psCan_SetHandler(XCanPs *psCanPtr); // Set interrupt handlers
// psCan_SetHandler(&psCan0);

void psCan_SendHandler(void *CallBackRef);
void psCan_RecvHandler(void *CallBackRef);
void psCan_ErrorHandler(void *CallBackRef);
void psCan_EventHandler(void *CallBackRef);

// 设置发送帧头
void psCan_SetTxFrameHeader(u32 *FramePtr, u32 stardardOrExtended, u32 message_id, u32 frame_data_length);
//psCan_SetTxFrameHeader(txFrame_ch1, STANDARD_FRAME, STANDARD_MESSAGE_ID_CH1, FRAME_DATA_LENGTH);

/*****************************************************************************/
/**
*
* Send a CAN frame.
*
* @param	psCanPtr is a pointer to the driver instance
*
* @return	XST_SUCCESS if successful, a driver-specific return code if not.
*
* @note
*
* This function waits until TX FIFO has room for at least one frame before
* sending a frame. So this function may block if the hardware is not built
* correctly.
*
******************************************************************************/
static int psCan_SendFrame(XCanPs *psCanPtr, u32 *txFramePtr)
{
    /*
   * Wait until TX FIFO has room.
   */
    while (XCanPs_IsTxFifoFull(psCanPtr) == TRUE)
        ;

    /*
   * Now send the frame.
   *
   * Another way to send a frame is keep calling XCanPs_Send() until it
   * returns XST_SUCCESS. No check on if TX FIFO is full is needed anymore
   * in that case.
   */
    int status;
    status = XCanPs_Send(psCanPtr, txFramePtr);
    if (status != XST_SUCCESS)
    {
    	xil_printf("send failed\r\n");
    }

    // xil_printf("send success!\r\n");

    return status;
}



/*****************************************************************************/
/**
*
* This function receives a frame and verifies its contents.
*
* @param	psCanPtr is a pointer to the driver instance.
*
* @return	XST_SUCCESS if successful, a driver-specific return code if not.
*
* @note
*
* This function waits until RX FIFO becomes not empty before reading a frame
* from it. So this function may block if the hardware is not built
* correctly.
*
******************************************************************************/
//static int psCan_RecvFrame(XCanPs *psCanPtr, u32 rxFramePtr)
//{
//    /*
//   * Wait until a frame is received.
//   */
//    while (XCanPs_IsRxEmpty(psCanPtr) == TRUE)
//        ;
//
//    /*
//   * Receive a frame and verify its contents.
//   */
//    int status;
//    status = XCanPs_Recv(psCanPtr, rxFramePtr);
//    if (status == XST_SUCCESS)
//    {
//        /*
//     * Verify Identifier and Data Length Code.
//     */
//        if (rxFramePtr[0] != (u32)XCanPs_CreateIdValue((u32)TEST_MESSAGE_ID, 0, 0, 0, 0))
//        {
//            return XST_LOOPBACK_ERROR;
//        }
//
//        if ((rxFramePtr[1] & ~XCANPS_DLCR_TIMESTAMP_MASK) != TxFrame[1])
//        {
//            return XST_LOOPBACK_ERROR;
//        }
//
//        /*
//     * Verify Data field contents.
//     */
//        u8 *recvFramePtr;
//        recvFramePtr = (u8 *)(&RxFrame[2]);
//        for (int index = 0; index < FRAME_DATA_LENGTH; index++)
//        {
//            if (*recvFramePtr == (u8)index)
//            {
//                recvFramePtr++;
//            }
//            else
//            {
//                return XST_LOOPBACK_ERROR;
//            }
//        }
//    }
//
//    return status;
//}



#endif
